#include "wl_audio.h"
#include "wl_malloc.h"
#include "quec_common.h"
#include "ql_rtos.h"
#include "ql_audio.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

typedef struct {
    int player_hdl;
    wl_audio_player_callback player_cb;
    wl_audio_end_callback player_end_cb;
    wl_bool has_exception;
}wl_audio_player;

typedef struct {
    int recorder_hdl;
    wl_audio_recorder_callback recorder_cb;
    wl_audio_end_callback recorder_end_cb;
    wl_bool has_exception;
}wl_audio_recorder;

typedef struct {
    wl_audio_player *p_cur_player;
    wl_audio_recorder *p_cur_recorder;
}wl_audio_ctx;

wl_audio_ctx g_audio_ctx;

wl_int32 wl_audio_init(void) {
    memset(&g_audio_ctx, 0, sizeof(wl_audio_ctx));
}

wl_int32 wl_audio_end(void) {
    if (g_audio_ctx.p_cur_recorder) {
        ql_pcm_record_deinit(g_audio_ctx.p_cur_recorder->recorder_hdl);
        wl_free(g_audio_ctx.p_cur_recorder);
        g_audio_ctx.p_cur_recorder = wl_null;
    }

    if (g_audio_ctx.p_cur_recorder) {
        ql_pcm_play_deinit(g_audio_ctx.p_cur_player->player_hdl);
        wl_free(g_audio_ctx.p_cur_player);
        g_audio_ctx.p_cur_player = wl_null;
    }
    
}

int wl_audio_recorder_cb(char *p_data, int len, enum_aud_record_state state) {
    if (g_audio_ctx.p_cur_recorder) {
        switch (state)
        {
	        case AUD_RECORD_ERROR: {
                g_audio_ctx.p_cur_recorder->has_exception = wl_true;
                if (g_audio_ctx.p_cur_recorder->recorder_end_cb) {
                    g_audio_ctx.p_cur_recorder->recorder_end_cb(g_audio_ctx.p_cur_recorder, -1);
                }
            }
            break;

	        case AUD_RECORD_DATA: {
                if (g_audio_ctx.p_cur_recorder->recorder_cb) {
                    g_audio_ctx.p_cur_recorder->recorder_cb(g_audio_ctx.p_cur_recorder, p_data, len);
                }
            }
            break;

	        case AUD_RECORD_FINISHED: {
                if (!g_audio_ctx.p_cur_recorder->has_exception && g_audio_ctx.p_cur_recorder->recorder_end_cb) {
                    g_audio_ctx.p_cur_recorder->recorder_end_cb(g_audio_ctx.p_cur_recorder, 0);
                }

                wl_free(g_audio_ctx.p_cur_recorder);
                g_audio_ctx.p_cur_recorder = wl_null;
            }
            break;
        }
    }
}

WL_AUDIO_HANDLE wl_audio_start_record(wl_audio_recorder_callback callback, wl_audio_end_callback end_callback) {
    if (g_audio_ctx.p_cur_recorder) {
        return g_audio_ctx.p_cur_recorder;
    }

    wl_audio_recorder *p_recorder = (wl_audio_recorder *)wl_malloc(sizeof(wl_audio_recorder));
    if (p_recorder) {
        memset(p_recorder, 0, sizeof(wl_audio_recorder));

        p_recorder->recorder_cb = callback;
        p_recorder->recorder_end_cb = end_callback;
        p_recorder->recorder_hdl = 1;

        ql_pcm_config config;
        config.samplerate = RECORD_PCM_RATE;
        config.channels = 1;
        ql_pcm_init(&config);
        ql_pcm_record_init(wl_audio_recorder_cb);
        g_audio_ctx.p_cur_recorder = p_recorder;
    }

    return p_recorder;
}

wl_int32 wl_audio_stop_record(WL_AUDIO_HANDLE handle) {
    wl_audio_recorder *p_recorder = (wl_audio_recorder *)handle;
    if (p_recorder) {
        ql_pcm_record_pause(p_recorder->recorder_hdl);
        ql_pcm_record_deinit(p_recorder->recorder_hdl);
    }
}

int wl_audio_player_cb(char *p_data, int len, enum_aud_player_state state) {

    if (g_audio_ctx.p_cur_player == wl_null) {
        return 
    }

    switch (state)
    {
        case AUD_PLAYER_ERROR: {
            g_audio_ctx.p_cur_player->has_exception = wl_true;
            if (g_audio_ctx.p_cur_player->player_end_cb) {
                g_audio_ctx.p_cur_player->player_end_cb(g_audio_ctx.p_cur_player, -1);
            }
        }
        break;

        case AUD_PLAYER_NODATA:
        case AUD_PLAYER_LESSDATA:
        case AUD_PLAYER_START: {
            if (g_audio_ctx.p_cur_player->player_cb) {
                g_audio_ctx.p_cur_player->player_cb(g_audio_ctx.p_cur_player);
            }
        }
        break;

        case AUD_PLAYER_FINISHED: {
            if (!g_audio_ctx.p_cur_player->has_exception && g_audio_ctx.p_cur_player->player_end_cb) {
                g_audio_ctx.p_cur_player->player_end_cb(g_audio_ctx.p_cur_player, 0);
            }

            wl_free(g_audio_ctx.p_cur_player);
            g_audio_ctx.p_cur_player = wl_null;
        }
        break;
    }
}

WL_AUDIO_HANDLE wl_audio_start_play(wl_audio_player_callback callback, wl_audio_end_callback end_callback) {
    if (g_audio_ctx.p_cur_player) {
        return g_audio_ctx.p_cur_player;
    }

    wl_audio_player *p_player = (wl_audio_player *)wl_malloc(sizeof(wl_audio_player));
    if (p_player) {
        memset(p_player, 0, sizeof(wl_audio_player));
        p_player->player_cb = callback;
        p_player->player_end_cb = end_callback;
        
        ql_pcm_config config;
        config.samplerate = PLAY_PCM_RATE;
        config.channels = 1;
        ql_pcm_init(&config);
        ql_pcm_play_init(wl_audio_player_cb);
        p_player->player_hdl = 1;
        g_audio_ctx.p_cur_player = p_player;
    }

    return p_player;
}

wl_int32 wl_audio_stop_play(WL_AUDIO_HANDLE handle) {
    wl_audio_player *p_player = (wl_audio_player *)handle;
    if (p_player) {
        ql_pcm_play_stop(p_player->player_hdl);
        ql_pcm_play_deinit(p_player->player_hdl);
    }
}

wl_int32 wl_audio_put_play_data(WL_AUDIO_HANDLE handle, wl_uint8* data, wl_uint32 data_size) {
    wl_audio_player *p_player = (wl_audio_player *)handle;
    if (p_player) {
        ql_pcm_play(p_player->player_hdl, data, data_size);
    }
}


#ifdef __cplusplus
}
#endif /* __cplusplus */